#include "bsp_myiic.h"
#include "bsp_I2C_IE.h"
#include "gd32f4xx_i2c.h"

#if USE_IC_MODE == I2C_IRQ_MODE
uint8_t i2c_buffer_transmitter[16];
uint8_t i2c_buffer_receiver[16];

volatile uint8_t*       i2c_txbuffer;
volatile uint8_t*       i2c_rxbuffer;
volatile uint16_t       i2c_nbytes;
volatile ErrStatus      status;
ErrStatus state = ERROR;
/*!
    \brief      enable the peripheral clock
    \param[in]  none
    \param[out] none
    \retval     none
*/
static void rcu_config(void)
{
    /* enable GPIOB clock */
    rcu_periph_clock_enable(RCU_GPIOB);
    /* enable I2C1 clock */
    rcu_periph_clock_enable(RCU_I2C1);
    /* enable I2C0 clock */
    rcu_periph_clock_enable(RCU_I2C0);
}

/*!
    \brief      cofigure the GPIO ports.
    \param[in]  none
    \param[out] none
    \retval     none
*/
static void gpio_config(void)
{
    /* I2C0 and I2C1 GPIO ports */
    /* connect PB6 to I2C0_SCL */
    gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_6);
    /* connect PB7 to I2C0_SDA */
    gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_7);
    /* connect PB10 to I2C1_SCL */
    gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_10);
    /* connect PB11 to I2C1_SDA */
    gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_11);

    /* configure I2C0 GPIO */
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_6);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_7);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
    /* configure I2C1 GPIO */
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_11);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_11);
}

/*!
    \brief      cofigure the I2C0 and I2C1 interfaces..
    \param[in]  none
    \param[out] none
    \retval     none
*/
static void i2c_config(void)
{
    /* configure I2C clock */
    i2c_clock_config(I2C0, 100000, I2C_DTCY_2);
    /* configure I2C address */
    i2c_mode_addr_config(I2C0, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, I2C0_SLAVE_ADDRESS7);
    /* enable I2C0 */
    i2c_enable(I2C0);
    /* enable acknowledge */
    i2c_ack_config(I2C0, I2C_ACK_ENABLE);
    i2c_clock_config(I2C1, 100000, I2C_DTCY_2);
    /* configure I2C address */
    i2c_mode_addr_config(I2C1, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, I2C1_SLAVE_ADDRESS7);
    /* enable I2C1 */
    i2c_enable(I2C1);
    /* enable acknowledge */
    i2c_ack_config(I2C1, I2C_ACK_ENABLE);
}

/*!
    \brief      cofigure the NVIC peripheral
    \param[in]  none
    \param[out] none
    \retval     none
*/
static void i2c_nvic_config(void)
{
    nvic_priority_group_set(NVIC_PRIGROUP_PRE1_SUB3);
    nvic_irq_enable(I2C0_EV_IRQn, 0, 3);
    nvic_irq_enable(I2C1_EV_IRQn, 0, 4);
    nvic_irq_enable(I2C0_ER_IRQn, 0, 2);
    nvic_irq_enable(I2C1_ER_IRQn, 0, 1);
}

void I2c_Master_config(void)
{
	rcu_config();
	gpio_config();
	i2c_config();
	i2c_nvic_config();
}

#elif USE_IC_MODE == I2C_DMA_MODE

#define I2C0_SLAVE_ADDRESS7      0x82
#define I2C1_SLAVE_ADDRESS7      0x72
#define ARRAYNUM(arr_nanme)      (uint32_t)(sizeof(arr_nanme) / sizeof(*(arr_nanme)))
#define I2C0_DATA_ADDRESS        0x40005410
#define I2C1_DATA_ADDRESS        0x40005810
#define I2C1_RX_BUF_SIZE         (ARRAYNUM(g_I2c0_Buff_Tx)-1)

uint8_t g_I2c0_Buff_Tx[] = "I2C DMA test";
uint8_t g_I2c1_Buff_Rx[I2C1_RX_BUF_SIZE];
__IO ErrStatus state = ERROR;

/*!
    \brief      cofigure the I2C0 and I2C1 interfaces
    \param[in]  none
    \param[out] none
    \retval     none
*/
void i2c_config(void)
{
	/* enable I2C1 clock */
    rcu_periph_clock_enable(RCU_I2C1);
    /* enable I2C0 clock */
    rcu_periph_clock_enable(RCU_I2C0);
    /* configure I2C0 clock */
    i2c_clock_config(I2C0, 100000, I2C_DTCY_2);
    /* configure I2C0 address */
    i2c_mode_addr_config(I2C0, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, I2C0_SLAVE_ADDRESS7);
    /* enable I2C0 */
    i2c_enable(I2C0);
    /* enable acknowledge */
    i2c_ack_config(I2C0, I2C_ACK_ENABLE);
    /* configure I2C1 clock */
    i2c_clock_config(I2C1, 100000, I2C_DTCY_2);
    /* configure I2C1 address */
    i2c_mode_addr_config(I2C1, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, I2C1_SLAVE_ADDRESS7);
    /* enable I2C1 */
    i2c_enable(I2C1);
    /* enable acknowledge */
    i2c_ack_config(I2C1, I2C_ACK_ENABLE);
}

void rcu_config(void)
{
    /* enable GPIOB clock */
    rcu_periph_clock_enable(RCU_GPIOB);
    /* enable I2C1 clock */
    rcu_periph_clock_enable(RCU_I2C1);
    /* enable I2C0 clock */
    rcu_periph_clock_enable(RCU_I2C0);
    /* enable DMA0 clock */
    rcu_periph_clock_enable(RCU_DMA0);
}

void i2c_dma_config(void)
{
    dma_parameter_struct dma_init_struct;

//    gpio_config();
	rcu_config();
    i2c_config();

    /* initialize DMA channel4 */
    dma_deinit(DMA0, DMA_CH4);
    dma_struct_para_init(&dma_init_struct);

    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_addr = (uint32_t)g_I2c1_Buff_Rx;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = I2C1_RX_BUF_SIZE;
    dma_init_struct.periph_addr = I2C1_DATA_ADDRESS;
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA0, DMA_CH4, &dma_init_struct);

    /* initialize DMA channel5 */
    dma_deinit(DMA0, DMA_CH5);
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_addr = (uint32_t)g_I2c0_Buff_Tx;
    dma_init_struct.periph_addr = I2C0_DATA_ADDRESS;
    dma_init_struct.priority = DMA_PRIORITY_HIGH;
    dma_init(DMA0, DMA_CH5, &dma_init_struct);
    
    /* wait until I2C bus is idle */
    while(i2c_flag_get(I2C0, I2C_FLAG_I2CBSY));

    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C0);

    /* wait until SBSEND bit is set */
    while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND));

    /* send slave address to I2C bus*/
    i2c_master_addressing(I2C0, I2C1_SLAVE_ADDRESS7, I2C_TRANSMITTER);

    /* wait until ADDSEND bit is set*/
    while(!i2c_flag_get(I2C1, I2C_FLAG_ADDSEND));
    while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND));
    /* clear ADDSEND bit */
    i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND);
    i2c_flag_clear(I2C1, I2C_FLAG_ADDSEND);
    
    /* enable I2C1 DMA */
    i2c_dma_enable(I2C1, I2C_DMA_ON);
    /* enable I2C0 DMA */
    i2c_dma_enable(I2C0, I2C_DMA_ON);
    /* enable DMA0 channel4 */
    dma_channel_enable(DMA0, DMA_CH4);
    /* enable DMA0 channel5 */
    dma_channel_enable(DMA0, DMA_CH5);

    /* DMA0 channel4 full transfer finish flag */
    while(!dma_flag_get(DMA0, DMA_CH4, DMA_FLAG_FTF));
    /* DMA0 channel5 full transfer finish flag */
    while(!dma_flag_get(DMA0, DMA_CH5, DMA_FLAG_FTF));

    /* send a stop condition to I2C bus*/
    i2c_stop_on_bus(I2C0);
    /* wait until stop condition generate */
    while(I2C_CTL0(I2C0)&0x0200);
    while(!i2c_flag_get(I2C1, I2C_FLAG_STPDET));
    /* clear the STPDET bit */
    i2c_enable(I2C1);
}

#else
void IIC_Init(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOE, &GPIO_InitStructure);
  IIC_SCL=1;
  IIC_SDA=1;
}

void IIC_Start(void)
{
	SDA_OUT();
	IIC_SDA=1;
	IIC_SCL=1;
	delay_us(4);
 	IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
	delay_us(4);
	IIC_SCL=0;
}	  

void IIC_Stop(void)
{
	SDA_OUT();//sda
	IIC_SCL=0;
	IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
 	delay_us(4);
	IIC_SCL=1; 
	IIC_SDA=1;
	delay_us(4);							   	
}

uint8_t IIC_Wait_Ack(void)
{
	uint8_t ucErrTime=0;
	SDA_IN();      //SDA
	IIC_SDA=1;delay_us(1);
	IIC_SCL=1;delay_us(1);
	while(READ_SDA)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	IIC_SCL=0;
	return 0;
}

void IIC_Ack(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=0;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}

void IIC_NAck(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=1;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}

void IIC_Send_Byte(uint8_t txd)
{
    uint8_t t;
	SDA_OUT();
    IIC_SCL=0;//
    for(t=0;t<8;t++)
    {
        IIC_SDA=(txd&0x80)>>7;
        txd<<=1; 	  
		delay_us(2);
		IIC_SCL=1;
		delay_us(2); 
		IIC_SCL=0;	
		delay_us(2);
    }	 
}

//?1???,ack=1?,??ACK,ack=0,??nACK   
uint8_t IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	SDA_IN();//SDA
    for(i=0;i<8;i++ )
	{
        IIC_SCL=0; 
        delay_us(2);
		IIC_SCL=1;
        receive<<=1;
        if(READ_SDA)receive++;
		delay_us(1);
    }
    if (!ack)
        IIC_NAck();
    else
        IIC_Ack();
    return receive;
}

//指定器件指定地址读取一个字节
//devices address slave
//ReadAddr 指定地址
//返回值uint8_t 读到的数据
uint8_t IIC_Read_One_Byte(uint8_t daddr,uint8_t addr)
{
   uint8_t temp=0;		  	    																 
   IIC_Start();//起始
   IIC_Send_Byte(daddr);   //发送器件地址+写指令
   IIC_Wait_Ack(); //等待应答
   IIC_Send_Byte(addr);   //发送寄存器地址
   IIC_Wait_Ack();	//等待应答    
   IIC_Start();  	 //重复起始条件	   
   IIC_Send_Byte(daddr+1); //发送器件指令+读指令
   IIC_Wait_Ack();	 
   temp=IIC_Read_Byte(0);	//不应答	   
   IIC_Stop();//产生一个停止条件	    
   return temp;
}
//指定器件指定地址写入一个字节
//devices address slave
//ReadAddr 指定地址
//DataToWrite 要写入的数据
void IIC_Write_One_Byte(uint8_t daddr,uint8_t addr,uint8_t data)
{
  IIC_Start(); //开启IIC
  IIC_Send_Byte(daddr);   //发送器件地址+写指令
  IIC_Wait_Ack();	   
  IIC_Send_Byte(addr);   //发送寄存器地址
  IIC_Wait_Ack(); 	 										  		   
  IIC_Send_Byte(data);     //发送字节数据							   
  IIC_Wait_Ack();  		    	   
  IIC_Stop();//产生一个停止条件 
  delay_ms(10);	 
}

void IIC_ReadmultiyBytes(uint8_t SlaveAddr,uint8_t RegAddr,uint8_t Len,uint8_t *Buf_Addr)
{
   uint8_t i;
   IIC_Start();
   IIC_Send_Byte(SlaveAddr);
   IIC_Wait_Ack();
   IIC_Send_Byte(RegAddr);
   IIC_Wait_Ack();  
   IIC_Start();
   IIC_Send_Byte(SlaveAddr+1);
   IIC_Wait_Ack();
   for(i=0;i<Len;i++)
   {
	  if(i!=Len-1) 
	  {
		 Buf_Addr[i]=IIC_Read_Byte(1);
	  }
	  else
	  {
		Buf_Addr[i]=IIC_Read_Byte(0);
	  }
   }
   IIC_Stop(); 
}
#endif
